/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    device_gpio.c
 *  @brief   Designware gpio device adapter layer
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  liuchao
 ****************************************************************/

#include "mem_map_table.h"
#include "device_gpio.h"
#include "dw_gpio.h"
#include "irq.h"

#define DW_GPIO_REG_BASE_PTR(base) ((DW_GPIO_REG_PTR)(long)base)

#if (USE_DW_GPIO_PORT_A)
static DEV_GPIO gpio_port_a;
static DW_GPIO_PORT dw_gpio_port_a;
static DEV_GPIO_HANDLER dw_gpio_bit_handler_a[GPIO_A_INT_MAX_COUNT];
static DW_GPIO_BIT_ISR dw_gpio_bit_isr_a = {
	GPIO_A_INT_MAX_COUNT, dw_gpio_bit_handler_a
};

static int32_t gpio_porta_open(uint32_t dir)
{
	return dw_gpio_open(&gpio_port_a, dir);
}

static int32_t gpio_porta_close(void)
{
	return dw_gpio_close(&gpio_port_a);
}

static int32_t gpio_porta_control(uint32_t ctrl_cmd, void *param)
{
	return dw_gpio_control(&gpio_port_a, ctrl_cmd, param);
}

static int32_t gpio_porta_write(uint32_t val, uint32_t mask)
{
	return dw_gpio_write(&gpio_port_a, val, mask);
}

static int32_t gpio_porta_read(uint32_t *val, uint32_t mask)
{
	return dw_gpio_read(&gpio_port_a, val, mask);
}

static void gpio_porta_isr(void *ptr)
{
	dw_gpio_isr_handler(&gpio_port_a, ptr);
}

static void gpio_porta_install(void)
{
	uint32_t i;
	DEV_GPIO_PTR port_ptr = &gpio_port_a;
	DEV_GPIO_INFO_PTR info_ptr = &(gpio_port_a.gpio_info);
	DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_a);

	info_ptr->gpio_ctrl = (void *)dw_port_ptr;
	info_ptr->opn_cnt = 0;
	info_ptr->method = 0;
	info_ptr->direction = 0;
	info_ptr->extra = 0;

	dw_port_ptr->obj_no = eGPIO_DEV_OBJ_0;
	dw_port_ptr->no = DW_GPIO_PORT_A;
	dw_port_ptr->regs = DW_GPIO_REG_BASE_PTR(MEM_MAP_GPIO_BASE_ADDR);
	dw_port_ptr->valid_bit_mask = GPIO_A_VALID_MASK;
	dw_port_ptr->intno = GPIO_IRQn;
	dw_port_ptr->int_handler = gpio_porta_isr;

	for (i = 0; i < dw_gpio_bit_isr_a.int_bit_max_cnt; i++) {
		dw_gpio_bit_isr_a.int_bit_handler_ptr[i] = NULL;
	}

	dw_port_ptr->gpio_bit_isr = &dw_gpio_bit_isr_a;

	dw_port_ptr->regs->SWPORTS[dw_port_ptr->no].CTRL = 0;

	port_ptr->gpio_open = gpio_porta_open;
	port_ptr->gpio_close = gpio_porta_close;
	port_ptr->gpio_control = gpio_porta_control;
	port_ptr->gpio_write = gpio_porta_write;
	port_ptr->gpio_read = gpio_porta_read;
}
#endif

#if (USE_DW_GPIO_PORT_B)
static DEV_GPIO gpio_port_b;
static DW_GPIO_PORT dw_gpio_port_b;

static int32_t gpio_portb_open(uint32_t dir)
{
	return dw_gpio_open(&gpio_port_b, dir);
}

static int32_t gpio_portb_close(void)
{
	return dw_gpio_close(&gpio_port_b);
}

static int32_t gpio_portb_control(uint32_t ctrl_cmd, void *param)
{
	return dw_gpio_control(&gpio_port_b, ctrl_cmd, param);
}

static int32_t gpio_portb_write(uint32_t val, uint32_t mask)
{
	return dw_gpio_write(&gpio_port_b, val, mask);
}

static int32_t gpio_portb_read(uint32_t *val, uint32_t mask)
{
	return dw_gpio_read(&gpio_port_b, val, mask);
}

static void gpio_portb_install(void)
{
	DEV_GPIO_PTR port_ptr = &gpio_port_b;
	DEV_GPIO_INFO_PTR info_ptr = &(gpio_port_b.gpio_info);
	DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_b);

	info_ptr->gpio_ctrl = (void *)dw_port_ptr;
	info_ptr->opn_cnt = 0;
	info_ptr->method = 0;
	info_ptr->direction = 0;
	info_ptr->extra = 0;

	dw_port_ptr->obj_no = eGPIO_DEV_OBJ_0;
	dw_port_ptr->no = DW_GPIO_PORT_A;
	dw_port_ptr->regs = DW_GPIO_REG_BASE_PTR(MEM_MAP_GPIO_BASE_ADDR);
	dw_port_ptr->valid_bit_mask = GPIO_B_VALID_MASK;
	dw_port_ptr->intno = 0;
	dw_port_ptr->int_handler = NULL;
	dw_port_ptr->gpio_bit_isr = NULL;

	dw_port_ptr->regs->SWPORTS[dw_port_ptr->no].CTRL = 0;

	port_ptr->gpio_open = gpio_portb_open;
	port_ptr->gpio_close = gpio_portb_close;
	port_ptr->gpio_control = gpio_portb_control;
	port_ptr->gpio_write = gpio_portb_write;
	port_ptr->gpio_read = gpio_portb_read;
}
#endif

#if (USE_DW_GPIO_PORT_C)
static DEV_GPIO gpio_port_c;
static DW_GPIO_PORT dw_gpio_port_c;

static int32_t gpio_portc_open(uint32_t dir)
{
	return dw_gpio_open(&gpio_port_c, dir);
}

static int32_t gpio_portc_close(void)
{
	return dw_gpio_close(&gpio_port_c);
}

static int32_t gpio_portc_control(uint32_t ctrl_cmd, void *param)
{
	return dw_gpio_control(&gpio_port_c, ctrl_cmd, param);
}

static int32_t gpio_portc_write(uint32_t val, uint32_t mask)
{
	return dw_gpio_write(&gpio_port_c, val, mask);
}

static int32_t gpio_portc_read(uint32_t *val, uint32_t mask)
{
	return dw_gpio_read(&gpio_port_c, val, mask);
}

static void gpio_portc_install(void)
{
	DEV_GPIO_PTR port_ptr = &gpio_port_c;
	DEV_GPIO_INFO_PTR info_ptr = &(gpio_port_c.gpio_info);
	DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_c);

	info_ptr->gpio_ctrl = (void *)dw_port_ptr;
	info_ptr->opn_cnt = 0;
	info_ptr->method = 0;
	info_ptr->direction = 0;
	info_ptr->extra = 0;

	dw_port_ptr->obj_no = eGPIO_DEV_OBJ_0;
	dw_port_ptr->no = DW_GPIO_PORT_C;
	dw_port_ptr->regs = DW_GPIO_REG_BASE_PTR(MEM_MAP_GPIO_BASE_ADDR);
	dw_port_ptr->valid_bit_mask = GPIO_C_VALID_MASK;
	dw_port_ptr->intno = 0;
	dw_port_ptr->int_handler = NULL;
	dw_port_ptr->gpio_bit_isr = NULL;

	dw_port_ptr->regs->SWPORTS[dw_port_ptr->no].CTRL = 0;

	port_ptr->gpio_open = gpio_portc_open;
	port_ptr->gpio_close = gpio_portc_close;
	port_ptr->gpio_control = gpio_portc_control;
	port_ptr->gpio_write = gpio_portc_write;
	port_ptr->gpio_read = gpio_portc_read;
}
#endif

#if (USE_DW_GPIO_PORT_D)
static DEV_GPIO gpio_port_d;
static DW_GPIO_PORT dw_gpio_port_d;

static int32_t gpio_portd_open(uint32_t dir)
{
	return dw_gpio_open(&gpio_port_d, dir);
}

static int32_t  gpio_portd_close(void)
{
	return dw_gpio_close(&gpio_port_d);
}

static int32_t  gpio_portd_control(uint32_t ctrl_cmd, void *param)
{
	return dw_gpio_control(&gpio_port_d, ctrl_cmd, param);
}

static int32_t  gpio_portd_write(uint32_t val, uint32_t mask)
{
	return dw_gpio_write(&gpio_port_d, val, mask);
}

static int32_t  gpio_portd_read(uint32_t *val, uint32_t mask)
{
	return dw_gpio_read(&gpio_port_d, val, mask);
}

static void  gpio_portd_install(void)
{
	DEV_GPIO_PTR port_ptr = &gpio_port_d;
	DEV_GPIO_INFO_PTR info_ptr = &(gpio_port_d.gpio_info);
	DW_GPIO_PORT_PTR dw_port_ptr = &(dw_gpio_port_d);

	info_ptr->gpio_ctrl = (void *)dw_port_ptr;
	info_ptr->opn_cnt = 0;
	info_ptr->method = 0;
	info_ptr->direction = 0;
	info_ptr->extra = 0;

	dw_port_ptr->obj_no = eGPIO_DEV_OBJ_0;
	dw_port_ptr->no = DW_GPIO_PORT_D;
	dw_port_ptr->regs = DW_GPIO_REG_BASE_PTR(MEM_MAP_GPIO_BASE_ADDR);
	dw_port_ptr->valid_bit_mask = GPIO_D_VALID_MASK;
	dw_port_ptr->intno = 0;
	dw_port_ptr->int_handler = NULL;
	dw_port_ptr->gpio_bit_isr = NULL;

	dw_port_ptr->regs->SWPORTS[dw_port_ptr->no].CTRL = 0;

	port_ptr->gpio_open = gpio_portd_open;
	port_ptr->gpio_close = gpio_portd_close;
	port_ptr->gpio_control = gpio_portd_control;
	port_ptr->gpio_write = gpio_portd_write;
	port_ptr->gpio_read = gpio_portd_read;
}
#endif

static void dw_gpio_all_install(void)
{
#if (USE_DW_GPIO_PORT_A)
	gpio_porta_install();
#endif
#if (USE_DW_GPIO_PORT_B)
	gpio_portb_install();
#endif
#if (USE_DW_GPIO_PORT_C)
	gpio_portc_install();
#endif
#if (USE_DW_GPIO_PORT_D)
	gpio_portd_install();
#endif

	return;
}

DEV_GPIO_PTR gpio_get_dev(int32_t dev, int32_t port)
{
	static uint32_t install_flag = 0;

	/* intall device objects */
	if (install_flag == 0) {
		install_flag = 1;
		dw_gpio_all_install();
	}

	switch (port) {
		case eGPIO_PORT_OBJ_A:
#if (USE_DW_GPIO_PORT_A)
			if (eGPIO_DEV_OBJ_0 == dev)
				return &gpio_port_a;

#endif
			break;

		case eGPIO_PORT_OBJ_B:
#if (USE_DW_GPIO_PORT_B)
			if (eGPIO_DEV_OBJ_0 == dev)
				return &gpio_port_b;

#endif
			break;

		case eGPIO_PORT_OBJ_C:
#if (USE_DW_GPIO_PORT_C)
			if (eGPIO_DEV_OBJ_0 == dev)
				return &gpio_port_c;

#endif
			break;

		case eGPIO_PORT_OBJ_D:
#if (USE_DW_GPIO_PORT_D)
			if (eGPIO_DEV_OBJ_0 == dev)
				return &gpio_port_d;

#endif
			break;

		default:
			break;
	}

	return NULL;
}

